<!doctype html>
<!--
This is a first hack, implemented by Oliver Labs in 2012
on the basis of several examples which can be found on the internet.

It shows a single graph of a function f(x,y).

Just to show that it is possible to implement with not too much effort.
This code is not well-structure, neither well-documented.
-->
<html>
    <head>
        <title>Oliver's First 3d Test</title>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, user-scalable=yes, minimum-scale=1.0, maximum-scale=1.0">
            
        <script src="vendor/three.js/Three.js"></script>
        <script src="vendor/three.js/Detector.js"></script>
        <!-- https://github.com/mrdoob/stats.js -->
        <script src="vendor/three.js/Stats.js"></script>

        <script src="vendor/threex/THREEx.screenshot.js"></script>
        <script src="vendor/threex/THREEx.FullScreen.js"></script>
        <script src="vendor/threex/THREEx.WindowResize.js"></script>
        <script src="vendor/dragpancontrols.js"></script>

        <link  href="css/main.css" rel="stylesheet"/>
    </head>
<body>
    <!-- three.js container -->
        <div id="container"></div>
    <!-- info on screen display -->
    <div id="info">
        <div class="top">
          Oliver's First 3d-graph Test!
</div>
<div id="mya"></div>
        <div class="bottom" id="inlineDoc" >
<!--            - <i>p</i> for screenshot  -->
        </div> 
    </div> 

<script type="text/javascript">
  var stats, scene, renderer, composer;
  var camera, cameraControl;

  var PIseconds = 0;

  var strF = "x*x";
  var strG = "y*y";
  var strH = "a*f(x,y) + b*g(x,y)";
  var graph3d;
  var xmin=-1, xmax=1;
  var ymin=-1, ymax=1;

  var a=1;
  var b=1;
    
  var geometry;
  var material;
  var planeMaterial;
  var mesh;

  var num = new Array(20, 20);

//  var currentlyPressedKeys = {};

  var camDist = 7;

  var kijNumX = 20;
  var kijNumY = 20;
  var kij = new Array(kijNumX+1, kijNumY+1); // a maximum number of 20 control points per direction 

  function myFunc() {
    alert("hi");
  }

  function init_kij() {
    var i,j;
    var mX = kijNumX / 2;
    var mY = kijNumY / 2;
    for(i=0; i<=kijNumX; i++) {
      for(j=0; j<=kijNumY; j++) {
        kij[i,j] = new THREE.Vector3(i/kijNumX, j/kijNumY, 1*(i-mX)*(j-mY)/kijNumX/kijNumY);
      }
    }
//  kij[1,1].z = 10;
  } // end of init_kij
    
  function setKij(i, j, z) {
    kij[i,j] = z;
  }
    
  function handleKeyDown(event) {
//    currentlyPressedKeys[event.keyCode] = true;

    if (String.fromCharCode(event.keyCode) == "O") {
      camDist *= 1.05;
    }
    if (String.fromCharCode(event.keyCode) == "I") {
      camDist /= 1.05;
    }
    if (String.fromCharCode(event.keyCode) == "1") {
      camDist = 7;
    }
//  alert("zoom: "+camDist+" ("+String.fromCharCode(event.keyCode)+")");
  }

  function handleKeyUp(event) {
//    currentlyPressedKeys[event.keyCode] = false;
  }
    
  if( !init() ) animate();
    
        // init the scene
  function init(){
        if( Detector.webgl ){
                renderer = new THREE.WebGLRenderer({
                    antialias       : true, // to get smoother output
                    preserveDrawingBuffer   : true  // to allow screenshot
                });
                renderer.setClearColorHex( 0xCCCCCC, 1 );
            }else{
                renderer    = new THREE.CanvasRenderer();
            }
            renderer.setSize( window.innerWidth*0.8, window.innerHeight*0.8 );
            document.getElementById('container').appendChild(renderer.domElement);

            // add Stats.js - https://github.com/mrdoob/stats.js
            stats = new Stats();
            stats.domElement.style.position = 'absolute';
            stats.domElement.style.bottom   = '0px';
            document.body.appendChild( stats.domElement );

            // create a scene
            scene = new THREE.Scene();

            // put a camera in the scene
            camera  = new THREE.PerspectiveCamera(35, window.innerWidth / window.innerHeight, 1, 10000 );
            camera.position.set(camDist, 0, 0);
            scene.add(camera);

            // create a camera contol
            cameraControls  = new THREE.TrackballControls( camera )
//                        cameraControls = new THREE.FlyControls(camera);

                        init_kij();

            // transparently support window resize
            THREEx.WindowResize.bind(renderer, camera);
            // allow 'p' to make screenshot
            THREEx.Screenshot.bindKey(renderer);
            // allow 'f' to go fullscreen where this feature is supported
            if( THREEx.FullScreen.available() ){
                THREEx.FullScreen.bindKey();        
//              document.getElementById('inlineDoc').innerHTML  += "- <i>f</i> for fullscreen";
            }

            // here you add your objects
            // - you will most likely replace this part by your own
            var light   = new THREE.AmbientLight( Math.random() * 0xffffff );
            scene.add( light );
            var light   = new THREE.DirectionalLight( Math.random() * 0xffffff );
            light.position.set( Math.random(), Math.random(), Math.random() ).normalize();
            scene.add( light );
            var light   = new THREE.DirectionalLight( Math.random() * 0xffffff );
            light.position.set( Math.random(), Math.random(), Math.random() ).normalize();
            scene.add( light );
            var light   = new THREE.PointLight( Math.random() * 0xffffff );
            light.position.set( Math.random()-0.5, Math.random()-0.5, Math.random()-0.5 )
                        .normalize().multiplyScalar(1.2);
            scene.add( light );
            var light   = new THREE.PointLight( Math.random() * 0xffffff );
            light.position.set( Math.random()-0.5, Math.random()-0.5, Math.random()-0.5 )
                        .normalize().multiplyScalar(1.2);
            scene.add( light );

  planeMaterial = new THREE.MeshBasicMaterial({color: 0xcc0000, transparent: false });

            geometry    = new THREE.TorusGeometry( 1, 0.42, 32, 32 );
            material    = new
               THREE.MeshPhongMaterial({ambient: 0x858585,
                 color: 0xbb0066, transparent: true});
                        material.opacity = 1.0;
            mesh    = new THREE.Mesh( geometry, material );

//                        mesh.geometry.dynamic = true;


var planeGeometry = new THREE.PlaneGeometry(50,50,1);
var plane = new THREE.Mesh(planeGeometry, planeMaterial);
plane.position.z = 0;
//scene.add(plane);

geometry = new THREE.Geometry();
create3dgraph();

                geometry.computeFaceNormals();

                graph3d = new THREE.Mesh( geometry, material );
                graph3d.geometry.dynamic = true;

               scene.add(graph3d);


  document.onkeydown = handleKeyDown;
  document.onkeyup = handleKeyUp;

        }

  function x(j) {
    return(xmin + (xmax-xmin)*j/num[1]);
  }

  function y(i) {
    return(ymin + (ymax-ymin)*i/num[0]);
  }

  function z(x,y) {
    return(h(x,y));
}


  function f(x,y) {
    return(eval(strF));
 }

  function g(x,y) {
    return(eval(strG));
  }

  function h(x,y) {
    return(eval(strH));
  }

 function update3dgraph() {
    var v;
    var i, j;
    var px, py;
//    kij[1,1].z = a;
//    kij[3,3].z = b;
    for(i=0; i<num[0]; i++) {
      for(j=0; j<num[1]; j++) {
       px = graph3d.geometry.vertices[i*num[1]+j].position.x;
       py = graph3d.geometry.vertices[i*num[1]+j].position.y;
       graph3d.geometry.vertices[i*num[1]+j].position.z = z(px,py);
      }
    }
    for(i=0; i<num[0]; i++) {
      for(j=0; j<num[1]; j++) {
       px = graph3d.geometry.vertices[num[0]*num[1]+ i*num[1]+j].position.x;
       py = graph3d.geometry.vertices[num[0]*num[1]+ i*num[1]+j].position.y;
       graph3d.geometry.vertices[num[0]*num[1]+ i*num[1]+j].position.z = z(px,py);
     }
   }
} // end of update3dgraph()

  function create3dgraph() {
    var v;
    var i, j;
    for(i=0; i<num[0]; i++) {
      for(j=0; j<num[1]; j++) {
        v = new THREE.Vector3(x(j), y(i), z(x(j),y(i)));
        geometry.vertices.push(new THREE.Vertex(v));
      }
    }
    for(i=0; i<num[0]; i++) {
      for(j=0; j<num[1]; j++) {
        v = new THREE.Vector3(x(j), y(i), z(x(j),y(i)));
        geometry.vertices.push(new THREE.Vertex(v));
      }
    }
   for(i=0; i<num[0]-1; i++) {
      for(j=0; j<num[1]-1; j++) {
       geometry.faces.push(new THREE.Face3(i*num[1]+j, i*num[1]+j+1, (i+1)*num[1]+j));
       geometry.faces.push(new THREE.Face3((i+1)*num[1]+j, i*num[1]+j+1, (i+1)*num[1]+j+1));
      }
    }    
   for(i=0; i<num[0]-1; i++) {
      for(j=0; j<num[1]-1; j++) {
       geometry.faces.push(new THREE.Face3(num[0]*num[1]+i*num[1]+j+1, num[0]*num[1]+i*num[1]+j,
        num[0]*num[1]+(i+1)*num[1]+j));
       geometry.faces.push(new THREE.Face3(num[0]*num[1]+i*num[1]+j+1, num[0]*num[1]+(i+1)*num[1]+j,
        num[0]*num[1]+(i+1)*num[1]+j+1));
      }
    }    
  } // end create3dgraph()

        // animation loop
        function animate() {

            // loop on request animation loop
            // - it has to be at the begining of the function
            // - see details at http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating
            requestAnimationFrame( animate );

            // do the render
            render();

            // update stats
            stats.update();
        }

        // render the scene
        function render() {
            // variable which is increase by Math.PI every seconds - usefull for animation
            PIseconds   = Date.now() * Math.PI;

            // update camera controls
            cameraControls.update();
var pos = camera.position;
pos.normalize();
pos.multiplyScalar(camDist);
camera.position = pos;

update3dgraph();

graph3d.geometry.__dirtyVertices = true;
graph3d.geometry.__dirtyNormals = true;
graph3d.geometry.computeFaceNormals();
graph3d.geometry.computeVertexNormals();

// actually render the scene
            renderer.render( scene, camera );
        }
    </script>
</body>
</html>
